package com.iwhalecloud.bss.kite.cucc.order.accept.chain.impl;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.iwhalecloud.bss.kite.common.constant.ErrorConsts;
import com.iwhalecloud.bss.kite.common.constant.KeyConsts;
import com.iwhalecloud.bss.kite.common.constant.SymbolConsts;
import com.iwhalecloud.bss.kite.common.constant.TableConsts;
import com.iwhalecloud.bss.kite.common.util.KiteBeanUtils;
import com.iwhalecloud.bss.kite.common.util.KiteListUtils;
import com.iwhalecloud.bss.kite.common.util.KiteObjectUtils;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.common.util.SeqUtils;
import com.iwhalecloud.bss.kite.cucc.order.accept.chain.AbstractOrderHandler;
import com.iwhalecloud.bss.kite.cucc.order.loader.IInstLoader;
import com.iwhalecloud.bss.kite.cucc.order.loader.InstLoaderFactory;
import com.iwhalecloud.bss.kite.cucc.order.util.AcceptUtils;
import com.iwhalecloud.bss.kite.dataservice.cache.DcPublicCache;
import com.iwhalecloud.bss.kite.dataservice.entity.DcPublic;
import com.iwhalecloud.bss.kite.dataservice.entity.OrderItem;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.IInst;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.OfferInst;
import com.iwhalecloud.bss.kite.dataservice.entity.inst.ProdInst;
import com.iwhalecloud.bss.kite.dataservice.entity.order.OrderItemChange;
import com.iwhalecloud.bss.kite.dataservice.enums.TableConfig;
import com.iwhalecloud.bss.kite.dataservice.mapper.order.OrderItemMapper;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.enums.RelType;
import com.iwhalecloud.bss.kite.manager.inst.KiteInst;
import com.iwhalecloud.bss.kite.manager.inst.change.KiteInstChange;
import com.iwhalecloud.bss.kite.manager.inst.change.KiteRelChange;
import com.iwhalecloud.bss.kite.manager.inst.graph.IRelType;
import com.iwhalecloud.bss.kite.manager.util.ManagerUtils;
import com.iwhalecloud.bss.kite.order.client.dto.InstContainer;
import com.iwhalecloud.bss.kite.order.client.dto.OrderContainer;
import com.iwhalecloud.bss.kite.order.client.dto.OrderRequest;
import com.iwhalecloud.bss.kite.order.client.proxy.InstContainerProxy;
import com.ztesoft.bss.base.staticdata.CoreDataInteract;
import com.ztesoft.bss.base.staticdata.CoreDataOffer;
import com.ztesoft.bss.common.util.SpringUtil;
import com.ztesoft.bss.order.base.consts.KeyValues;
import com.ztesoft.bss.order.base.consts.KeyValuesLocal;
import com.ztesoft.zsmart.core.log.ZSmartLogger;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <Description> <br>
 * 订单受理流程：订单项对象构造
 * @author xiao.xuzhang<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2020年2月13日 <br>
 * @since R9.0<br>
 * @see com.iwhalecloud.bss.kite.cucc.order.accept.chain.impl <br>
 */
@Component
public class OrderAssembleHandler extends AbstractOrderHandler {

    private static final ZSmartLogger LOGGER = ZSmartLogger.getLogger(OrderAssembleHandler.class);

    private static Map<InstType, String> instTypeTableNameMappings = ImmutableMap.<InstType, String>builder()
        .put(InstType.PROD_INST, TableConsts.ProdInst.getTableName().toUpperCase())
        .put(InstType.PROD_INST_FUNC, TableConsts.ProdInstFunc.getTableName().toUpperCase())
        .put(InstType.PROD_INST_ACCT, TableConsts.ProdInstAcctRel.getTableName().toUpperCase())
        .put(InstType.PROD_INST_STATE, TableConsts.ProdInstState.getTableName().toUpperCase())
        .put(InstType.SUB_PROD_INST, TableConsts.SubProdInst.getTableName().toUpperCase())
        .put(InstType.MKT_RES_INST, TableConsts.OfferResInstRelExt.getTableName().toUpperCase())
        .put(InstType.OFFER_INST_ASSURE, TableConsts.OfferInstAssureExt.getTableName().toUpperCase())
        .put(InstType.GIFT_OFFER_INST, TableConsts.OfferInst.getTableName().toUpperCase())
        .put(InstType.MAIN_OFFER_INST, TableConsts.OfferInst.getTableName().toUpperCase())
        .put(InstType.PROMOTION_OFFER_INST, TableConsts.OfferInst.getTableName().toUpperCase())
        .put(InstType.ADDITIONAL_OFFER_INST, TableConsts.OfferInst.getTableName().toUpperCase())
        .put(InstType.BASE_OFFER_INST, TableConsts.OfferInst.getTableName().toUpperCase()).build();

    @Override
    public void doHandle(OrderRequest request) {
        request.setAcceptDate(LocalDateTime.now());
        List<OfferInst> offerInsts = InstContainer.ofRequest(request).listOfferInsts();
        // 可选包销售品实例和actionType=K的不生成订单
        List<OfferInst> offerInstList = offerInsts.stream().filter(offerInst -> {
            return !(Objects.equals(CoreDataOffer.OFF_0005_12, offerInst.getOfferType())
            || Objects.equals(ActionType.K.name(), offerInst.getActionType())
                     || Objects.equals(ActionType.K.name(), offerInst.getNewActionType()));
        }).collect(Collectors.toList());

        Assert.notEmpty(offerInstList, "The offerInst cannot be empty when orderItem is created");
        for (OfferInst offerInst : offerInstList) {
            createOrderItem(request, offerInst);
        }
    }

    /**
     * Description: <br>
     * 创建订单对象
     * @author xiao.xuzhang<br>
     * @taskId <br>
     * @param request
     * @param compInst <br>
     */
    private OrderItem createOrderItem(OrderRequest request, OfferInst compInst) {
        OrderItem orderItem = new OrderItem();

        String orderItemId = SeqUtils.genOrderItemId(request.getLanId());
        orderItem.setOrderItemId(orderItemId);
        orderItem.setAskId(orderItemId);
        orderItem.setCustOrderId(request.getCustOrderId());
        orderItem.setAcceptMode(request.getAcceptMode());
        orderItem.setOrderSource(request.getAskSource());
        // 订单项类型：销售品类
        orderItem.setOrderItemCd(CoreDataInteract.EVT_0003_1200);
        // 订单项状态：受理中
        orderItem.setStatusCd(CoreDataInteract.EVT_0001_100000);
        orderItem.setStatusDate(LocalDateTime.now());
        if (CoreDataInteract.EVT_C_0003_1100.equals(request.getOrderContainer().getCustomerOrder().getOperType())) {
            orderItem.setOperType(CoreDataInteract.EVT_C_0003_1100);
        }
        else {
            orderItem.setOperType(CoreDataInteract.EVT_C_0003_1000);
        }
        orderItem.setUndoFlag("F");

        orderItem.setApplyObjSpec(compInst.getOfferId());
        orderItem.setObjId(compInst.getOfferInstId());
        orderItem.setOfferKind(compInst.getOfferType());
        orderItem.setAccNbr(getOrderAccNbr(request, compInst));
        orderItem.setBelongLanId(compInst.getLanId());
        orderItem.setRegionId(compInst.getRegionId());

        orderItem.setAcceptRegionId(request.getRegionId());
        orderItem.setAcceptStaffId(request.getStaffId());
        orderItem.setAcceptLanId(request.getLanId());
        orderItem.setCreateOrgId(request.getOrgId());
        orderItem.setAcceptDate(request.getAcceptDate());
        orderItem.setCreateDate(request.getAcceptDate());
        orderItem.setCreateStaff(request.getStaffId());
        orderItem.setCreatePost(request.getPostId());
        orderItem.setUpdatePost(request.getPostId());
        orderItem.setUpdateOrg(request.getOrgId());
        orderItem.setOrderHandlerId(request.getStaffId());
        orderItem.setCustWorksheetId(orderItemId);
        orderItem.setPreHandleFlag("0");
        orderItem.setServiceOfferId(request.getServiceOfferId());
        orderItem.setIsCharge("00F");
        orderItem.setVerNum("0");
        orderItem.setParOrderItemId("-1");
        orderItem.setPriority("0");
        orderItem.setSkipOpen("F");
        orderItem.setBelongCustId(request.getCustId());
        orderItem.setNewBelongCustId(request.getCurrentCustId());
        //处理order_item.remark字段,从公共属性获取
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        String remark = querySceneInstService.getCommonAttrValue(request.getMainSceneInstId(), "remark");
        orderItem.setRemark(remark);
        orderItem.setOldOrderItemId(getOldOrderItemId(request, compInst));
        resetOrderItem(orderItem, compInst);

        // 创建订单项的变动信息
        List<OrderItemChange> orderItemChanges = createOrderItemChanges(request, orderItem);
        request.getOrderContainer().getOrderItemChangeMap().put(orderItemId, orderItemChanges);
        if (CollectionUtils.isNotEmpty(orderItemChanges) || isAllowEmptyOrderItemChange(orderItem.getServiceOfferId())) {
            // 有变动信息才生成订单项
            OrderContainer.ofRequest(request).addOrderItem(orderItem);
        }

        return orderItem;
    }

    /**
     * 需要判断order_item中对于的产品实例是否已经是新装在途 如果已经是新装在途 那么需要将该单修改为修正单
     * @param orderItem
     */
    private void resetOrderItem(OrderItem orderItem, OfferInst compInst) {
        if (!KeyValues.OFFER_KIND_0.equals(compInst.getOfferType())) {
            return;
        }
        if (!AcceptUtils.isOnwayInst(compInst)) {
            return;
        }
        OrderItemMapper orderItemMapper = SpringUtil.getBean(OrderItemMapper.class);
        Example example = new Example(OrderItem.class);
        example.createCriteria().andEqualTo("belongCustId", orderItem.getBelongCustId())
            .andEqualTo("objId", orderItem.getObjId()).andEqualTo("operType", CoreDataInteract.EVT_C_0003_1000)
            .andEqualTo("serviceOfferId", KeyValuesLocal.XINGOU_SERVICE);
        OrderItem oldOrderItem = orderItemMapper.selectOneByExample(example);
        if (Objects.isNull(oldOrderItem)) {
            // 兼容跨客户套餐受理
            example.clear();
            example.createCriteria().andEqualTo("belongCustId", compInst.getOwnerCustId())
                .andEqualTo("objId", orderItem.getObjId()).andEqualTo("operType", CoreDataInteract.EVT_C_0003_1000)
                .andEqualTo("serviceOfferId", KeyValuesLocal.XINGOU_SERVICE);
            oldOrderItem = orderItemMapper.selectOneByExample(example);
        }
        if (!KiteObjectUtils.isEmpty(oldOrderItem)) {
            orderItem.setOperType(CoreDataInteract.EVT_C_0003_1100);
            orderItem.setOldOrderItemId(oldOrderItem.getOrderItemId());
            orderItem.setServiceOfferId(oldOrderItem.getServiceOfferId());
        }
    }

    /**
     * 获取旧订单项id
     * 筛选同一实例的旧订单项，优先取缓存中的订单项id，若没有，获取相同服务提供的订单项id，若没有，取一笔相同销售品的订单项id
     * @param request
     * @param compInst
     * @return
     */
    private String getOldOrderItemId(OrderRequest request, OfferInst compInst) {
        List<OrderItem> oldOrderItems = request.getOrderContainer().getOldOrderItems();
        if (KiteListUtils.isEmpty(oldOrderItems)) {
            return null;
        }
        IQuerySceneInstService querySceneInstService = SpringUtil.getBean(IQuerySceneInstService.class);
        String oldOrderItemId = querySceneInstService.getExtParameter(request.getMainSceneInstId())
            .get(KeyConsts.CORRECT_ORDER_ITEM_ID_KEY) + "";

        List<OrderItem> targetOrderItems = oldOrderItems.stream()
            .filter(t -> KiteStringUtils.equals(compInst.getOfferInstId(), t.getObjId())).collect(Collectors.toList());
        if (KiteListUtils.isEmpty(targetOrderItems)) {
            return null;
        }

        List<OrderItem> tarOrderItems = targetOrderItems.stream()
            .filter(t -> KiteStringUtils.equals(oldOrderItemId, t.getOrderItemId())).collect(Collectors.toList());
        if (!KiteListUtils.isEmpty(tarOrderItems)) {
            return oldOrderItemId;
        }

        tarOrderItems = targetOrderItems.stream()
            .filter(t -> KiteStringUtils.equals(request.getServiceOfferId(), t.getServiceOfferId()))
            .collect(Collectors.toList());
        if (!KiteListUtils.isEmpty(tarOrderItems)) {
            return tarOrderItems.get(0).getOrderItemId();
        }

        return targetOrderItems.get(0).getOrderItemId();
    }

    /**
     * 获取订单项业务号码
     * @param request
     * @param compInst
     * @return
     */
    private String getOrderAccNbr(OrderRequest request, OfferInst compInst) {
        String accNum = null;
        if (Objects.equals(CoreDataOffer.OFF_0005_10, compInst.getOfferType())) {
            ProdInst prodInst = request.getInstContainer().getProdInstMap().get(compInst.getOfferInstId());
            Assert.notNull(prodInst, "prodInst cannot be null");
            return prodInst.getAccNum();
        }
        return accNum;
    }

    /**
     * 是否允许没有订单项变动信息生成订单项
     * @return
     */
    private boolean isAllowEmptyOrderItemChange(String serviceOfferId) {
        if (StringUtils.isBlank(serviceOfferId)) {
            return false;
        }

        List<DcPublic> dcPublics = DcPublicCache.get("2020041301"); // DcPublicCache.get(DcPublicConsts.STYPE_ALLOW_EMPTY_ORDER_ITEM_CHANGE_SERVICE_OFFER);
        if (CollectionUtils.isEmpty(dcPublics)) {
            return false;
        }

        for (DcPublic dcPublic : dcPublics) {
            String codea = dcPublic.getCodea();
            if (StringUtils.isBlank(codea)) {
                continue;
            }

            codea = new StringBuilder().append(",").append(codea.trim()).append(",").toString();
            String str = new StringBuilder().append(",").append(serviceOfferId.trim()).append(",").toString();
            if (codea.indexOf(str) > -1) {
                return true;
            }
        }

        return false;
    }

    /**
     * 创建订单的变动信息
     * @param request
     * @param orderItem
     * @return
     */
    private List<OrderItemChange> createOrderItemChanges(OrderRequest request, OrderItem orderItem) {
        List<OrderItemChange> orderItemChanges = Lists.newArrayList();
        InstContainerProxy instContainer = InstContainer.ofRequest(request);
        OfferInst offerInst = instContainer.getOfferInst(orderItem.getObjId());
        Assert.notNull(offerInst, "offerInst cannot be null");
        if (Objects.equals(CoreDataOffer.OFF_0005_10, orderItem.getOfferKind())) {
            ProdInst prodInst = request.getInstContainer().getProdInstMap().get(offerInst.getOfferInstId());
            Assert.notNull(prodInst, "prodInst cannot be null");

            orderItemChanges.addAll(createOrderItemChanges(request, orderItem, InstType.PROD_INST,
                prodInst.getProdInstId(), prodInst.getProdId()));

            instContainer.listOfferResInstRelExts(offerInst.getCompInstId()).forEach(offerResInstRelExt -> {
                orderItemChanges.addAll(createOrderItemChanges(request, orderItem, InstType.MKT_RES_INST,
                    offerResInstRelExt.getOfferResInstRelId(), offerResInstRelExt.getProdId()));
            });

            instContainer.listProdInstFuncs(prodInst.getProdInstId()).forEach(prodInstFunc -> {
                orderItemChanges.addAll(createOrderItemChanges(request, orderItem, InstType.PROD_INST_FUNC,
                    prodInstFunc.getProdInstId(), prodInstFunc.getProdId()));
            });

            instContainer.listProdInstAcctRels(prodInst.getProdInstId()).forEach(prodInstAcctRel -> {
                orderItemChanges.addAll(createOrderItemChanges(request, orderItem, InstType.PROD_INST_ACCT,
                    prodInstAcctRel.getProdInstAcctRelId(), null));
            });

            instContainer.listProdInstStates(prodInst.getProdInstId()).forEach(prodInstState -> {
                orderItemChanges.addAll(createOrderItemChanges(request, orderItem, InstType.PROD_INST_STATE,
                    prodInstState.getProdInstStateId(), null));
            });

            instContainer.listOfferInstAssureExts(prodInst.getCompInstId()).forEach(offerInstAssureExt -> {
                orderItemChanges.addAll(createOrderItemChanges(request, orderItem, InstType.OFFER_INST_ASSURE,
                    offerInstAssureExt.getOfferInstAssureExtId(), null));
            });

            instContainer.listSubProdInsts(prodInst.getCompInstId()).forEach(subProdInst -> {
                orderItemChanges.addAll(createOrderItemChanges(request, orderItem, InstType.SUB_PROD_INST,
                    subProdInst.getProdInstId(), subProdInst.getProdId()));
            });
        }

        // 销售品实例变动信息
        orderItemChanges
            .addAll(createOrderItemChanges(request, orderItem, AcceptUtils.getOfferInstType(offerInst.getOfferType()),
                offerInst.getOfferInstId(), offerInst.getOfferId()));

        instContainer.listAdditionalOfferInsts(offerInst.getOfferInstId()).forEach(additionalOfferInst -> {
            orderItemChanges.addAll(createOrderItemChanges(request, orderItem,
                AcceptUtils.getOfferInstType(additionalOfferInst.getOfferType()),
                additionalOfferInst.getOfferInstId(), additionalOfferInst.getOfferId()));
        });

        return orderItemChanges;
    }

    /**
     * 创建实例和实例关系的变动信息
     * @param request
     * @param orderItem
     * @param instType
     * @param instId
     * @param specId
     * @return
     */
    private List<OrderItemChange> createOrderItemChanges(OrderRequest request, OrderItem orderItem, InstType instType,
        String instId, String specId) {
        List<OrderItemChange> orderItemChanges = Lists.newArrayList();
        // 实例变动信息
        String key = ManagerUtils.join(instType, instId);
        List<KiteInstChange> instChange = request.getInstChangeMap().get(key);
        orderItemChanges.addAll(createOrderItemChangesOfInst(request, orderItem, specId, instChange));
        // 实例关系变动信息
        List<KiteRelChange> relChanges = request.getRelChangeMap().get(key);
        orderItemChanges.addAll(createOrderItemChangesOfInstRel(request, orderItem, specId, relChanges));
        return orderItemChanges;
    }

    /**
     * 创建实例变动信息
     * @param request
     * @param orderItem
     * @param specId
     * @param instChanges
     * @return
     */
    private List<OrderItemChange> createOrderItemChangesOfInst(OrderRequest request, OrderItem orderItem, String specId,
        List<KiteInstChange> instChanges) {
        List<OrderItemChange> orderItemChanges = new ArrayList<>();
        if (CollectionUtils.isEmpty(instChanges)) {
            return orderItemChanges;
        }

        String oldActionType = "";
        String actionType = "";
        KiteInstChange instChange = instChanges.stream()
            .filter(p -> StringUtils.equalsAny(p.getActionType().name(), ActionType.A.name(), ActionType.D.name()))
            .findFirst().orElse(null);

        if (Objects.nonNull(instChange)) {
            String tableName = instTypeTableNameMappings.get(instChange.getSubInstType());
            if (StringUtils.isBlank(tableName)) {
                return orderItemChanges;
            }

            IInst inst = InstContainer.ofRequest(request).getInst(tableName, instChange.getSubInstId());
            if (Objects.isNull(inst)) {
                return orderItemChanges;
            }

            IInstLoader<IInst> instLoader = InstLoaderFactory.getInstLoader(tableName);
            IInst oldInst = instLoader.getInst(tableName, instChange.getSubInstId(), inst.getOwnerCustId());
            oldActionType = oldInst != null ? oldInst.getActionType() : null;
            actionType = ManagerUtils.getEnumName(instChange.getActionType());
            OrderItemChange orderItemChange = genOrderItemChange(instChange, orderItem, specId, oldActionType, actionType);
            if (Objects.nonNull(orderItemChange)) {
                orderItemChanges.add(orderItemChange);
            }
        }
        else {
            // 生成实例属性订单变动信息
            orderItemChanges.addAll(genModOrderItemChanges(instChanges, orderItem, specId));
        }

        return orderItemChanges;
    }

    /**
     * 创建实例关系变动信息
     * @param request
     * @param orderItem
     * @param specId
     * @param relChanges
     * @return
     */
    private List<OrderItemChange> createOrderItemChangesOfInstRel(OrderRequest request, OrderItem orderItem,
        String specId, List<KiteRelChange> relChanges) {
        List<OrderItemChange> orderItemChanges = Lists.newArrayList();
        if (CollectionUtils.isEmpty(relChanges)) {
            return orderItemChanges;
        }

        Map<String, List<KiteRelChange>> relChangeMap = groupRelChanges(relChanges);
        relChangeMap.forEach((key, relChangeList) -> {
            List<KiteRelChange> newRelChanges = filterRelChanges(relChangeList);
            for (KiteRelChange relChange : newRelChanges) {
                if (StringUtils.equalsAny(relChange.getFieldName(), KiteInst.ACTION_TYPE, "action_type")
                    && !StringUtils.equalsAny(relChange.getNewValue(), ActionType.A.name(), ActionType.D.name())) {
                    continue;
                }

                String tableName = relType2TableName(relChange.getRelType());
                if (StringUtils.isBlank(tableName)) {
                    continue;
                }

                // 接入产品实例和功能产品实例关系
                if (Objects.equals(RelType.PROD_REL_TYPE_100600, relChange.getRelType())) {
                    continue;
                }

                String actionType = null;
                String oldActionType = null;
                String instRelId = null;
                String sourceInstId = relChange.getSourceInstId();
                String targetInstId = relChange.getTargetInstId();

                if (Objects.equals(RelType.OFFER_PROD_REL_TYPE, relChange.getRelType().getType())
                    && Objects.equals(InstType.PROD_INST, relChange.getSourceInstType())) {
                    // 基础销售品和功能产品的offerProdInstRel关系，把sourceInstId改为基础销售品实例id
                    ProdInst prodInst = InstContainer.ofRequest(request).getProdInst(sourceInstId);
                    if (Objects.nonNull(prodInst)) {
                        sourceInstId = prodInst.getCompInstId();
                    }
                }

                String relTypeCode = Optional.ofNullable(relChange.getRelType()).map(IRelType::getCode).orElse("");
                IInst inst = InstContainer.ofRequest(request).getInstRel(tableName, sourceInstId, targetInstId, relTypeCode);
                if (Objects.isNull(inst)) {
                    if (Objects.equals(RelType.OFFER_OBJ_REL_TYPE_1000, relChange.getRelType())) {
                        // 礼包销售品实例和套餐、促销包销售品实例的关系由于历史原因用错了OFFER_OBJ_REL_TYPE_1000
                        inst = InstContainer.ofRequest(request).getOfferObjInstRel(sourceInstId, targetInstId,
                            RelType.OFFER_OBJ_REL_TYPE_110000.getCode());
                    }
                    else if (Objects.equals(RelType.OFFER_PROD_REL_TYPE_1000, relChange.getRelType())) {
                        ProdInst prodInst = InstContainer.ofRequest(request).getProdInst(sourceInstId);
                        inst = InstContainer.ofRequest(request).getOfferProdInstRel(prodInst.getCompInstId(), targetInstId,
                            RelType.OFFER_PROD_REL_TYPE_1000.getCode());
                    }
                }

                if (Objects.isNull(inst)) {
                    continue;
                }

                TableConfig tableConfig = EnumUtils.getEnum(TableConfig.class, tableName);
                if (Objects.isNull(tableConfig)) {
                    ErrorConsts.BUSI_COMMON_ERROR.throwOut("no table config [TableConfig." + tableName + "]");
                }

                actionType = AcceptUtils.getActionType(inst);
                instRelId = KiteBeanUtils.getValueByName(inst, tableConfig.getIdField());

                IInstLoader<IInst> instLoader = InstLoaderFactory.getInstLoader(tableName);
                IInst oldInst = instLoader.getInst(tableName, instRelId, inst.getOwnerCustId());
                oldActionType = oldInst != null ? oldInst.getActionType() : null;

                String instStateChg = AcceptUtils.computeInstChgByAction(oldActionType, actionType);
                if (StringUtils.isBlank(instStateChg)) {
                    LOGGER.error("cannot compute instStateChg by oldActionType[{}] and newActionType[{}]",
                        oldActionType, actionType);
                    continue;
                }

                String fieldName = AcceptUtils.transformOrderItemChangeField(relChange.getFieldName());
                String fieldValue = relChange.getNewValue();
                String oldFieldValue = relChange.getOldValue();
                if (StringUtils.equalsAny(relChange.getFieldName(), KiteInst.ACTION_TYPE, "action_type")
                    && StringUtils.equalsAny(relChange.getNewValue(), ActionType.A.name(), ActionType.D.name())) {
                    // 新增、删除的实例关系把fieldName、fieldValue、oldFieldValue置空
                    fieldName = "";
                    fieldValue = "";
                    oldFieldValue = "";
                }

                OrderItemChange orderItemChange = new OrderItemChange();
                orderItemChange.setChgId(SeqUtils.getNext(TableConsts.OrderItemChange));
                orderItemChange.setTableName(tableName);
                orderItemChange
                    .setActionType(Objects.equals(ActionType.A.name(), actionType) ? actionType : ActionType.M.name());
                orderItemChange.setInstId(instRelId);
                orderItemChange.setFieldName(fieldName);
                orderItemChange.setFieldValue(fieldValue);
                orderItemChange.setOldFieldValue(oldFieldValue);
                orderItemChange.setCompInstId(orderItem.getObjId());
                orderItemChange.setCustOrderId(orderItem.getCustOrderId());
                orderItemChange.setOrderItemId(orderItem.getOrderItemId());
                orderItemChange.setHandleTime(new Date());
                orderItemChange.setCustId(orderItem.getBelongCustId());
                orderItemChange.setSpecId(specId);
                orderItemChange.setInstStateChg(instStateChg);
                orderItemChanges.add(orderItemChange);
            }
        });

        return orderItemChanges;
    }

    /**
     * 对相同的实例关系分组
     * @param relChanges
     * @return
     */
    private Map<String, List<KiteRelChange>> groupRelChanges(List<KiteRelChange> relChanges) {
        if (CollectionUtils.isEmpty(relChanges)) {
            return new HashMap<>();
        }

        return relChanges.stream().collect(Collectors.groupingBy(relChange -> {
            String sourceInstType = ManagerUtils.getEnumName(relChange.getSourceInstType());
            String sourceInstId = relChange.getSourceInstId();
            String targetInstType = ManagerUtils.getEnumName(relChange.getTargetInstType());
            String targetInstId = relChange.getTargetInstId();
            String relType = ManagerUtils.getEnumName(relChange.getRelType());
            return StringUtils.join(
                Lists.newArrayList(sourceInstType, sourceInstId, targetInstType, targetInstId, relType),
                SymbolConsts.PIPELINE);
        }));
    }

    /**
     * 过滤相同实例关系的变动信息
     * <li>如果有actionType=A(新增)或actionType=D(删除)的变动信息，只保留一条actionType的变动信息
     * <li>否则过滤actionType的变动信息，只保留属性的变动信息
     * @param relChanges
     * @return
     */
    private List<KiteRelChange> filterRelChanges(List<KiteRelChange> relChanges) {
        if (CollectionUtils.isEmpty(relChanges)) {
            return new ArrayList<>();
        }

        KiteRelChange actionTypeChange = null;
        List<KiteRelChange> otherChanges = new ArrayList<>();
        for (KiteRelChange relChange : relChanges) {
            if (StringUtils.equalsAny(relChange.getFieldName(), KiteInst.ACTION_TYPE, "action_type")) {
                if (StringUtils.equalsAny(relChange.getNewValue(), ActionType.A.name(), ActionType.D.name())) {
                    // 实例关系新增或删除的变动信息
                    actionTypeChange = relChange;
                    break;
                }
            }
            else {
                // 实例关系上属性的变动信息，非actionType的变动信息
                otherChanges.add(relChange);
            }
        }

        List<KiteRelChange> relChangeList = new ArrayList<>();
        if (Objects.nonNull(actionTypeChange)) {
            relChangeList.add(actionTypeChange);
        }
        else {
            relChangeList.addAll(otherChanges);
        }

        return relChangeList;
    }

    /**
     * 生成实例属性订单变动信息
     * @param instChanges
     * @param orderItem
     * @param specId
     * @return
     */
    private List<OrderItemChange> genModOrderItemChanges(List<KiteInstChange> instChanges, OrderItem orderItem,
        String specId) {
        List<OrderItemChange> orderItemChanges = Lists.newArrayList();
        KiteInstChange actionTypeChange = instChanges.stream()
            .filter(t -> KiteInst.ACTION_TYPE.equals(t.getFieldName()) || "action_type".equals(t.getFieldName()))
            .findFirst().orElse(null);
        String oldActionType = ActionType.K.name();
        String actionType = ActionType.M.name();
        if (Objects.nonNull(actionTypeChange)) {
            oldActionType = actionTypeChange.getOldValue();
            actionType = actionTypeChange.getNewValue();
        }

        for (KiteInstChange instChange : instChanges) {
            if (StringUtils.equalsAny(instChange.getFieldName(), KiteInst.ACTION_TYPE, "action_type")) {
                continue;
            }

            OrderItemChange orderItemChange = genOrderItemChange(instChange, orderItem, specId, oldActionType, actionType);
            if (Objects.nonNull(orderItemChange)) {
                orderItemChanges.add(orderItemChange);
            }
        }
        return orderItemChanges;
    }

    /**
     * 生成变动信息对象
     * @param instChange
     * @param orderItem
     * @param specId
     * @param oldActionType
     * @param actionType
     * @return
     */
    private OrderItemChange genOrderItemChange(KiteInstChange instChange, OrderItem orderItem, String specId,
        String oldActionType, String actionType) {
        OrderItemChange orderItemChange = new OrderItemChange();
        orderItemChange.setChgId(SeqUtils.getNext(TableConsts.OrderItemChange));
        orderItemChange.setActionType(
            Objects.equals(ActionType.A, instChange.getActionType()) ? ActionType.A.name() : ActionType.M.name());
        orderItemChange.setTableName(instTypeTableNameMappings.get(instChange.getSubInstType()));
        orderItemChange.setInstId(instChange.getSubInstId());
        orderItemChange.setFieldName(AcceptUtils.transformOrderItemChangeField(instChange.getFieldName()));
        orderItemChange.setFieldValue(instChange.getNewValue());
        orderItemChange.setOldFieldValue(instChange.getOldValue());
        orderItemChange.setCompInstId(orderItem.getObjId());
        orderItemChange.setCustOrderId(orderItem.getCustOrderId());
        orderItemChange.setOrderItemId(orderItem.getOrderItemId());
        orderItemChange.setHandleTime(new Date());
        orderItemChange.setCustId(orderItem.getBelongCustId());
        orderItemChange.setSpecId(specId);
        String instStateChg = AcceptUtils.computeInstChgByAction(oldActionType, actionType);
        // 无效变动
        if (KiteStringUtils.isEmpty(instStateChg)) {
            return null;
        }
        orderItemChange.setInstStateChg(instStateChg);
        if (StringUtils.equalsAny(AcceptUtils.computAciontType(orderItemChange.getInstStateChg()),
            KeyValues.ACTION_TYPE_A, KeyValues.ACTION_TYPE_D)) {
            orderItemChange.setFieldName("");
            orderItemChange.setFieldValue("");
            orderItemChange.setOldFieldValue("");
        }
        return orderItemChange;
    }

    /**
     * 根据关系类型获取对应的实例关系表名
     * @param relType
     * @return
     */
    private static String relType2TableName(IRelType relType) {
        if (RelType.PROD_REL_TYPE.equals(relType.getType())) {
            return TableConsts.ProdInstRel.getTableName().toUpperCase();
        }
        else if (RelType.OFFER_OBJ_REL_TYPE.equals(relType.getType())) {
            return TableConsts.OfferObjInstRel.getTableName().toUpperCase();
        }
        else if (RelType.OFFER_PROD_REL_TYPE.equals(relType.getType())) {
            return TableConsts.OfferProdInstRel.getTableName().toUpperCase();
        }
        return null;
    }
}
